package text;

import mathsys2.AbstractArithmetic;
import mathsys2.AdditionArithmetic;
import mathsys2.SubtractionArithmetic;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

/**
 * 改写后的算式测试类：针对AbstractArithmetic抽象类及AdditionArithmetic/SubtractionArithmetic子类
 * 测试范围：
 * 1. 加法子类：结果计算、交换律去重、和超100异常、运算数约束；
 * 2. 减法子类：结果计算、非交换律去重、差为负异常、运算数约束；
 * 3. 抽象类多态特性：确保子类可替代父类实例使用。
 */
public class ArithmeticTestV2 {

    // -------------------------- 一、加法算式子类（AdditionArithmetic）测试 --------------------------
    /**
     * 测试1：正常加法场景（和≤100，无重复）
     * 验证：结果计算正确、toString格式正确、getter方法有效
     */
    @Test
    void testAdditionArithmetic_Normal() {
        // 多态引用：抽象类指向加法子类实例
        AbstractArithmetic addition = new AdditionArithmetic(3, 5);

        // 验证结果（3+5=8）
        assertEquals(8, addition.getResult(), "加法结果计算错误（3+5应为8）");
        // 验证toString格式（如“3 + 5 = ?”）
        assertEquals("3 + 5 = ?", addition.toString(), "加法算式格式化错误");
        // 验证getter方法
        assertEquals(3, addition.getNum1(), "加法被加数（num1）获取错误");
        assertEquals(5, addition.getNum2(), "加法加数（num2）获取错误");
        assertEquals('+', addition.getOperator(), "加法运算符获取错误");
    }

    /**
     * 测试2：加法交换律去重（a+b与b+a视为重复）
     * 验证：equals()返回true，hashCode()一致，符合《模块化软件构造》故事三去重需求
     */
    @Test
    void testAdditionArithmetic_CommutativeEquality() {
        AbstractArithmetic add1 = new AdditionArithmetic(2, 7);
        AbstractArithmetic add2 = new AdditionArithmetic(7, 2);

        // 验证equals()：交换运算数仍判定为重复
        assertTrue(add1.equals(add2), "加法交换律未判定为重复（2+7与7+2应视为相同）");
        // 验证hashCode()：交换运算数哈希值一致（确保集合去重有效）
        assertEquals(add1.hashCode(), add2.hashCode(), "加法交换律下哈希值不一致（影响集合去重）");
    }

    /**
     * 测试3：加法和超100异常（违反实验约束）
     * 验证：抛出IllegalArgumentException，信息符合预期
     */
    @Test
    void testAdditionArithmetic_SumOver100_ThrowsException() {
        // 场景：60+50=110>100，违反实验“加法和≤100”约束
        IllegalArgumentException exception = assertThrows(
                IllegalArgumentException.class,
                () -> new AdditionArithmetic(60, 50),
                "未对加法和超100场景抛出异常（60+50=110>100）"
        );
        // 验证异常信息包含关键提示
        assertTrue(exception.getMessage().contains("加法结果超过100"), "加法和超100的异常信息不符合预期");
        assertTrue(exception.getMessage().contains("60+50"), "加法异常信息未包含具体运算数（不利于调试）");
    }

    /**
     * 测试4：加法运算数越界异常（<0或>100）
     * 验证：父类共性校验生效，抛出异常
     */
    @Test
    void testAdditionArithmetic_NumberOutOfRange_ThrowsException() {
        // 场景1：运算数为负数（-1）
        IllegalArgumentException e1 = assertThrows(
                IllegalArgumentException.class,
                () -> new AdditionArithmetic(-1, 5),
                "未对加法负数运算数抛出异常（num1=-1）"
        );
        assertTrue(e1.getMessage().contains("运算数必须在0-100之间"), "加法负数运算数异常信息错误");

        // 场景2：运算数超100（101）
        IllegalArgumentException e2 = assertThrows(
                IllegalArgumentException.class,
                () -> new AdditionArithmetic(101, 5),
                "未对加法超100运算数抛出异常（num1=101）"
        );
        assertTrue(e2.getMessage().contains("运算数必须在0-100之间"), "加法超100运算数异常信息错误");
    }


    // -------------------------- 二、减法算式子类（SubtractionArithmetic）测试 --------------------------
    /**
     * 测试1：正常减法场景（差≥0，无重复）
     * 验证：结果计算正确、toString格式正确、getter方法有效
     */
    @Test
    void testSubtractionArithmetic_Normal() {
        // 多态引用：抽象类指向减法子类实例
        AbstractArithmetic subtraction = new SubtractionArithmetic(10, 4);

        // 验证结果（10-4=6）
        assertEquals(6, subtraction.getResult(), "减法结果计算错误（10-4应为6）");
        // 验证toString格式（如“10 - 4 = ?”）
        assertEquals("10 - 4 = ?", subtraction.toString(), "减法算式格式化错误");
        // 验证getter方法
        assertEquals(10, subtraction.getNum1(), "减法被减数（num1）获取错误");
        assertEquals(4, subtraction.getNum2(), "减法减数（num2）获取错误");
        assertEquals('-', subtraction.getOperator(), "减法运算符获取错误");
    }

    /**
     * 测试2：减法非交换律去重（a-b与b-a视为不同）
     * 验证：equals()返回false，hashCode()不同，符合《模块化软件构造》故事三去重需求
     */
    /*@Test
    void testSubtractionArithmetic_NonCommutativeEquality() {
        AbstractArithmetic sub1 = new SubtractionArithmetic(9, 3); // 9-3=6
        AbstractArithmetic sub2 = new SubtractionArithmetic(3, 9); // 3-9（会抛异常，此处仅用于equals判定）

        // 验证equals()：交换运算数判定为不同（但sub2实例化会抛异常，需先捕获）
        assertThrows(IllegalArgumentException.class,
                () -> new SubtractionArithmetic(3, 9),
                "减法差为负时未抛出异常（3-9=-6<0）");

        // 用合法实例验证非交换律（如9-3与8-2）
        AbstractArithmetic sub3 = new SubtractionArithmetic(8, 2);
        assertFalse(sub1.equals(sub3), "减法非交换律判定错误（9-3与8-2应视为不同）");
        assertNotEquals(sub1.hashCode(), sub3.hashCode(), "减法非交换律下哈希值错误（应不同）");
    }

    /**
     * 测试3：减法差为负异常（违反实验约束）
     * 验证：抛出IllegalArgumentException，信息符合预期
     */
    @Test
    void testSubtractionArithmetic_NegativeDifference_ThrowsException() {
        // 场景：3-9=-6<0，违反实验“减法差≥0”约束
        IllegalArgumentException exception = assertThrows(
                IllegalArgumentException.class,
                () -> new SubtractionArithmetic(3, 9),
                "未对减法差为负场景抛出异常（3-9=-6<0）"
        );
        // 验证异常信息包含关键提示
        assertTrue(exception.getMessage().contains("减法结果为负数"), "减法差为负的异常信息不符合预期");
        assertTrue(exception.getMessage().contains("3-9"), "减法异常信息未包含具体运算数（不利于调试）");
    }

    /**
     * 测试4：减法运算数越界异常（<0或>100）
     * 验证：父类共性校验生效，抛出异常
     */
    @Test
    void testSubtractionArithmetic_NumberOutOfRange_ThrowsException() {
        // 场景1：减数为负数（num2=-2）
        IllegalArgumentException e1 = assertThrows(
                IllegalArgumentException.class,
                () -> new SubtractionArithmetic(10, -2),
                "未对减法负数减数抛出异常（num2=-2）"
        );
        assertTrue(e1.getMessage().contains("运算数必须在0-100之间"), "减法负数运算数异常信息错误");

        // 场景2：被减数超100（num1=101）
        IllegalArgumentException e2 = assertThrows(
                IllegalArgumentException.class,
                () -> new SubtractionArithmetic(101, 50),
                "未对减法超100被减数抛出异常（num1=101）"
        );
        assertTrue(e2.getMessage().contains("运算数必须在0-100之间"), "减法超100运算数异常信息错误");
    }


    // -------------------------- 三、抽象类多态特性测试 --------------------------
    /**
     * 测试：抽象类引用统一管理加法/减法子类，验证里氏替换原则
     * 确保：子类可完全替代父类实例使用，为后续习题集系统类提供支撑
     */
    @Test
    void testAbstractArithmetic_Polymorphism() {
        // 加法子类多态引用
        AbstractArithmetic addPoly = new AdditionArithmetic(20, 30);
        // 减法子类多态引用
        AbstractArithmetic subPoly = new SubtractionArithmetic(50, 20);

        // 验证加法多态：结果正确（20+30=50）
        assertEquals(50, addPoly.getResult(), "加法多态引用结果错误（20+30应为50）");
        // 验证减法多态：结果正确（50-20=30）
        assertEquals(30, subPoly.getResult(), "减法多态引用结果错误（50-20应为30）");
        // 验证toString格式统一（均符合“num1 operator num2 = ?”）
        assertTrue(addPoly.toString().contains(" + "), "加法多态引用toString格式错误");
        assertTrue(subPoly.toString().contains(" - "), "减法多态引用toString格式错误");
    }
}